package com.honry.common.domain.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@SuppressWarnings("rawtypes")
public class DomainEventPublisher {
	private DomainEventPublisher(){
		//设置为未发布
		this.setPublishing(false);
		//初始化订阅List
		this.ensureSubscribersList();
	}
	/**
	 * 保证每个线程中只有一个实例
	 */
	private static final ThreadLocal<DomainEventPublisher> instance=new ThreadLocal<DomainEventPublisher>(){
		@Override
		protected DomainEventPublisher initialValue(){
			return new DomainEventPublisher();
		}
	};
	//发布状态
	private boolean publishing;
	//是否处于发布状态
	private boolean isPublishing(){
		return this.publishing;
	}
	//设置发布状态
	private void setPublishing(boolean aFlag){
		this.publishing=aFlag;
	}
	//订阅者
	private List subscribers;
	//仿C#属性风格
	
	private List subscribers(){
		return this.subscribers;
	}
	//设置订阅者
	private void setSubscribers(List aSubscriberList){
		this.subscribers=aSubscriberList;
	}
	//检查订阅者是否NULL
	private boolean hasSubscribers(){
		return this.subscribers()!=null;
	}
	//确保订阅者数据不为NULL
	private void ensureSubscribersList(){
		if(!this.hasSubscribers())
		{
			this.setSubscribers(new ArrayList());
		}
	}
	/**
	 * 简单工厂
	 * @return
	 */
	public static DomainEventPublisher instance(){
		return instance.get();
	}
	/**
	 * 发布事件
	 * @param aDomainEvent
	 */
	@SuppressWarnings("unchecked")
	public <T> void publish(final T aDomainEvent){
		//如果还没有发布，并且有订阅者
		if(!this.isPublishing()&&this.hasSubscribers()){
			try {
				//设为正在发布
				this.setPublishing(true);
				Class<?> eventType = aDomainEvent.getClass();
				//获取所有订阅者
				List<DomainEventSubscriber<T>> allSubscribers = this.subscribers;
				//循环发布
				for(DomainEventSubscriber<T> subscriber:allSubscribers){
					Class<?> subscribedToType=subscriber.subscribedToEventType();
					if(eventType == subscribedToType||subscribedToType==DomainEvent.class)
					{
						subscriber.handleEvent(aDomainEvent);
					}
				}
			} finally {
				//发布结束
				this.setPublishing(false);
			}
		}
	}
	
	/**
	 * 发布传入的所有事件
	 * @param aDomainEvents
	 */
	public void publishAll(Collection<DomainEvent> aDomainEvents){
		for(DomainEvent domainEvent:aDomainEvents){
			this.publish(domainEvent);
		}
	}
	/**
	 * 重置事件订阅
	 */
	public void reset(){
		//不在发布中，把所有订阅者清空
		if(!this.isPublishing()){
			this.setSubscribers(null);
		}
	}
	/**
	 * 订阅
	 * @param aSubscriber
	 */
	@SuppressWarnings("unchecked")
	public <T> void subscribe(DomainEventSubscriber<T> aSubscriber){
		
		if(!this.isPublishing())
		{
			this.ensureSubscribersList();
			this.subscribers.add(aSubscriber);
		}
	}
}
